let qall = a => document.querySelectorAll(a);
let qone = a => document.querySelector(a);
let historys = [];
let historyIndex = -1;

function toggle_dir_open(elm) {
    elm = elm.parentElement;
    
    if(elm.classList.contains('open')) {
        elm.classList.remove('open');
    } else {
        elm.classList.add('open');
    }
}

function init_code_fold(elm) {
    elm.querySelectorAll('pre.hljs code:not(.fold-animation)').forEach(code => {
        code.style.maxHeight = code.offsetHeight + 'px';
        code.parentElement.classList.remove('nofold');
        code.parentElement.classList.remove('folded');
        
        if(code.offsetHeight < 450) {
            code.parentElement.classList.add('nofold');
        }  else {
            code.parentElement.classList.add('folded');
        }
    });

    setTimeout(() => {
        elm.querySelectorAll('pre.hljs code:not(.fold-animation)').forEach(code => code.classList.add('fold-animation'));
    }, 100);
}

function init_mermaid(selector) {
    if(window.mermaid) {
        mermaid.startOnLoad = false;
        mermaid.init({startOnLoad: false, noteMargin: 10}, selector);
    }
}

/**
 * 激活文档
 * @param elm
 * @param option
 */
function active_doc(elm, option) {
    option = option || {};
    
    if(!elm) {
        return;
    }

    document.querySelectorAll('li.file-catalog-item').forEach( row => {
        row.classList.remove('active');
    });
    
    let cur = elm;
    let counter = 0;
    while(counter < 50) {
        counter ++;
        cur = cur.parentElement ? cur.parentElement.closest('li.dir') : null;
        
        if(cur) {
            cur.classList.add('open');
        } else {
            break;
        }
    }

    elm.classList.add('active');
    let path = elm.getAttribute('path');
    let result= parse_hash(window.location.hash);
    result.file = path;
    
    if(!option.fromInit) {
        result.navigator = '';
    }
    
    if(!option.fromHistory) {
        add_history(unparse_hash(result));
    }
    
    update_hash(result, true);

    let target = elm.getAttribute('target');
    let content = document.getElementById(target);
    content.parentNode.querySelectorAll(':scope > .md-content').forEach( row => {
        row.style.display = "none";
    });

    content.style.display = "";
    qall('html,body').forEach(row => row.scrollTop = 0);
    document.title = (elm.firstChild && elm.firstChild.nodeValue) || elm.innerText;

    init_code_fold(content);
    init_mermaid(content.querySelectorAll(`div.mermaid:not([data-processed])`));
    render_navigator_content();
    active_navigator_item();
}

let tipTimer = null;

function tip(msg) {
    let tip = document.getElementById('tip');
    tip.innerHTML = msg;
    
    clearTimeout(tipTimer);
    tip.classList.add('show');
    
    setTimeout(function () {
        tip.classList.remove('show');
    }, 3000);
}

function expand_code(elm) {
    let pre = elm.parentElement.parentElement;
    pre.classList.remove('folded');
}

function fold_code(elm) {
    let pre = elm.parentElement.parentElement;
    pre.classList.add('folded');
}

function copy_code(elm) {
    let input = document.getElementById('copy-input');
    input.value = Object.prototype.toString.call(elm) == Object.prototype.toString.call('')
            ? elm : elm.parentElement.parentElement.querySelector(":scope > code").innerText;
    input.select();
    
    if(document.execCommand('copy')) {
        tip(`复制成功 (${input.value.length} 字)`);
    }
}

function parse_hash(hash) {
    hash = hash[0] == '#' ? hash.substr(1) : hash;
    let result = {file:null, navigator:null};
    if(-1 == hash.indexOf('?')) {
        result.file = decodeURIComponent(hash);
    } else {
        let [file, navigator] = hash.split('?');
        result.file = decodeURIComponent(file);
        result.navigator = decodeURIComponent(navigator);
    }
    
    return result;
}

let ignoreHashChangeEventCounter = 0;
function unparse_hash(result) {
    return result.file + (result.navigator ? '?' + result.navigator : '');
}


function update_hash(hashInfo, ignoreHashChange) {
    let hash = unparse_hash(hashInfo);
    
    if(unescape(window.location.hash) != '#'+hash) {
        if(ignoreHashChange) {
            ignoreHashChangeEventCounter ++
        }
        
        window.location.hash = hash;
    }
}

(function() {
    document.querySelectorAll('img').forEach(row => {
        if(row.getAttribute('base64-src')) {
            row.src = Params.resources [row.getAttribute('base64-src')];
        }
    });
    
    // if(!Params.sourceIsDir) {
    //     init_mermaid(`div.mermaid:not([data-processed])`);
    //     init_code_fold(document);
    // }
})();


function show_navigator() {
    let elm = qone('#navigatorWrap');
    elm.classList.add('show');
    localStorage.setItem('NAVIGATOR_OPEN', 1);
}

function hide_navigator() {
    let elm = qone('#navigatorWrap');
    elm.classList.remove('show');
    localStorage.removeItem('NAVIGATOR_OPEN');
}

function toggle_navigator() {
    let elm = qone('#navigatorWrap');
    if(elm.classList.contains('show')) {
        hide_navigator();
    } else {
        show_navigator();
    }
}

function get_actived_menu_item() {
    return qone('.file-catalog li.file-catalog-item.active');
}

function get_actived_content_elm() {
    let elm = get_actived_menu_item();
    let target = elm.getAttribute('target');
    return qone('#' + target);
}

let temHiTimeout = null;

function scroll_to_content_head(elm) {
    if(typeof elm == 'string') {
        elm = qone(elm);
    }
    
    ani_scroll_top(document.documentElement, elm.offsetTop+1, _ => {
        elm.classList.remove('tem-hi');
        elm.classList.add('tem-hi');
        elm.scrollAniTimer = elm.scrollAniTimer ? elm.scrollAniTimer : null;
        
        clearTimeout(elm.scrollAniTimer);
        elm.scrollAniTimer = setTimeout(function () {
            elm.classList.remove('tem-hi');
        }, 300);
    });
}

function ani_scroll_top(elm, target, finish) {
    clearInterval(elm._scrollTimer);
    let scrollHeight = elm.scrollHeight - elm.clientHeight;
    
    if(target > scrollHeight) {
        elm._targetScrollTop = scrollHeight
    } else if(target <= 0) {
        elm._targetScrollTop = 0;
    } else {
        elm._targetScrollTop = target;
    }
    
    elm._targetDirect = target - elm.scrollTop;
    elm._targetSpeed = Math.abs((Math.abs(elm._targetScrollTop)-elm.scrollTop)/(300/10));
    elm._targetSpeed = elm._targetSpeed <= 0 ? 1 : elm._targetSpeed;
    
    if(!elm._targetDirect) {
        finish && finish();
        return;
    }
    
    elm._scrollTimer = setInterval(_ => {
        if(elm._targetDirect <= 0) {
            let offset = Math.round(elm.scrollTop - elm._targetSpeed);
            
            if(offset <= elm._targetScrollTop || offset <= 0) {
                elm.scrollTop = elm._targetScrollTop;
                clearInterval(elm._scrollTimer);
                finish && finish();
            } else {
                elm.scrollTop -= elm._targetSpeed;
            }
        } else {
            let offset = Math.round(elm.scrollTop + elm._targetSpeed);
            
            if(offset >= elm._targetScrollTop || offset >= scrollHeight) {
                elm.scrollTop = elm._targetScrollTop;
                clearInterval(elm._scrollTimer);
                finish && finish();
            } else {
                elm.scrollTop += elm._targetSpeed;
            }
        }
    }, 10);
}

function active_navigator_item() {
    let content = get_actived_content_elm();
    let menuItem = get_actived_menu_item();
    let heads = content.querySelectorAll('h1,h2,h3,h4,h5,h6');
    let scrollTop = document.documentElement.scrollTop;
    let activeHead = heads[0];
    
    for(let i=0; i<heads.length; i++) {
        let head = heads[i];
        let next = heads[i+1];
        
        if(scrollTop >= head.offsetTop) {
            if(!next || scrollTop < next.offsetTop) {
                activeHead = head;
                break;
            }
        }
    }
    
    function set_target_active(head, set) {
        let target = head.getAttribute('target');
        target = menuItem.querySelector('#' + target);
        
        if(target) {
            if(set) {
                ani_scroll_top(target.parentNode,  target.offsetTop - (target.parentNode.offsetHeight/2) + (target.offsetHeight /2));
                // target.parentNode.scrollTop = target.offsetTop - (target.parentNode.offsetHeight/2) + (target.offsetHeight /2);
                target.classList.add('active');
            } else {
                target.classList.remove('active');
            }
        }
    }
    
    for(let i=0; i<heads.length; i++) {
        set_target_active(heads[i], false);
    }
    
    if(activeHead) {
        set_target_active(activeHead, true);
    }
}

/**
 * 右上角导航菜单
 */
function render_navigator_content() {
    let menuItem = get_actived_menu_item();
    let target = menuItem.getAttribute('target');
    // let navigator = qone('#navigatorContent');
    
    //移除所有目录
    let allNavigator = qall('.file-catalog .navigator');
    for(let i=0; i<allNavigator.length; i++) {
        let elm = allNavigator[i];
        // elm.parentNode.removeChild(elm);
        elm.classList.remove('show');
    }
    
    let navigator = menuItem.querySelector('.navigator');
    let content = qone('#' + target);
    
    let fisrtHead = content.querySelector('h1');
    fisrtHead = fisrtHead ? fisrtHead : content.querySelector('h2');
    if(fisrtHead) {
        document.title = fisrtHead.innerText;
    }
    
    if(!navigator) {
        let heads = content.querySelectorAll('h1,h2,h3,h4,h5,h6');
        navigator = document.createElement('ul');
        navigator.classList.add('navigator');
        navigator.addEventListener('click', function(e) {
            e.stopPropagation();
            e.preventDefault();
        });
    
        navigator.addEventListener('mousewheel', function(e) {
            if(
                (e.deltaY > 0 && navigator.scrollTop+navigator.offsetHeight >= navigator.scrollHeight)
                    || (e.deltaY < 0 && navigator.scrollTop <= 0)
            ) {
                e.preventDefault();
                e.stopPropagation();
                console.log('stop', e.deltaY , navigator.scrollTop, navigator.scrollHeight);
                return false;
            }
    
            console.log('', e.deltaY , navigator.scrollTop, navigator.scrollHeight);
        })
        
        let increment = 1;
        navigator.innerHTML = '';
        let headList = [];
        
        for(let head of heads) {
            let headTag = head.tagName.toLowerCase();
            let headLevel = headTag.substr(1);
        
            let hid = target + '__head_' + increment;
            let lid = 'navigator__head_' + increment;
            let li = document.createElement('li');
        
            if('' == head.innerText.replace(/^\s+|\s+$/g, '')) {
                continue;
            }
    
            let headText = head.innerText.trim();
            headList.splice(headLevel-1);
            headList[headLevel-1] = headLevel == 1 ? '' : headText;
            
            let navigatorStr = headList.filter(Boolean).join('//')
            li.setAttribute('id', lid);
            li.setAttribute('target', hid);
            li.classList.add('hl-' + headLevel);
            li.setAttribute('title', navigatorStr);
            li.innerHTML = head.innerHTML;
            li.onclick = function() {
                scroll_to_content_head(head);
            }
        
            if(!head._setCopy && head.querySelector('.link')) {
                 head.querySelector('.link').onmouseup = (function(increment) {
                    return function (e) {
                        let result = parse_hash(window.location.hash);
                        
                        if(increment == 1) {
                            result.navigator = '';
                        } else {
                            result.navigator = navigatorStr;
                        }
                        
                        if(e.button == 1) {
                            let hash = '#' + unparse_hash(result).replace(/ /g, '%20');
                            copy_code(hash);
                        } else {
                            result.navigator = encodeURIComponent(result.navigator);
                            result.file = encodeURIComponent(result.file);
                            let hash = '#' + unparse_hash(result);
                            copy_code(window.location.href.replace(/#.*/, hash));
                        }
                    };
                 })(increment);
            }
        
            head.setAttribute('id', hid);
            head.setAttribute('target', lid);
            navigator.appendChild(li);
            increment ++;
        }
    
        menuItem.appendChild(navigator);
    }
    
    navigator.classList.add('show');
}

let scrollTimer = null;
window.onscroll = function () {
    clearTimeout(scrollTimer);
    scrollTimer = setTimeout(active_navigator_item, 100);
};

function active_doc_from_hash(hash, option) {
    option = option || {};
    hash = typeof hash == 'undefined' ? location.hash : hash;
    let hashInfo = parse_hash(hash);
    let {file, navigator} = hashInfo;
    let menuItem = get_actived_menu_item();
    let currentPath = null;
    
    if(menuItem) {
        currentPath = menuItem.getAttribute('path');
    }
    
    add_history(hash);
    
    if(Params.sourceIsDir && (!currentPath || currentPath != file)) {
        let active = false;
        
        if(file) {
            let all = qall('body > .body > .file-catalog li.file-catalog-item');
            
            for(let i=0; i<all.length; i++) {
                let row = all[i];
                
                if(row.getAttribute('path') == file) {
                    active = true;
                    active_doc(row, Object.assign(option, {fromHistory:true,fromInit:true}));
                    break;
                }
            }
        }
        
        if(!active) {
            active_doc(qone('.file-catalog li.file-catalog-item'), Object.assign(option, {fromHistory:true,fromInit:true}));
        }
    }
    
    if(!Params.actived && !Params.sourceIsDir) {
        Params.actived = true;
        active_doc(qone('.file-catalog li.file-catalog-item'), Object.assign(option, {fromHistory:true,fromInit:true}));
    }
    
    if(navigator) {
        setTimeout(_ => {
            let menuItem = get_actived_menu_item();
            let all = menuItem.querySelectorAll('.navigator li');
            
            for(let i=0; i<all.length; i++) {
                let row = all[i];
                
                if(row.getAttribute('title') == navigator) {
                    row.onclick();
                    break;
                }
            }
        }, 100);
    } else {
        active_navigator_item();
    }
    
    hashInfo = parse_hash(location.hash);
    hashInfo.navigator = '';
    
    if(!Params.sourceIsDir) {
        hashInfo.file = '-';
    }
    
    update_hash(hashInfo, true);
}

function init() {
    //导航
    // (function() {
    //     let elm = qone('#navigatorWrap .icon');
    //
    //     if(elm) {
    //         elm.onclick = function () {
    //             toggle_navigator();
    //         }
    //     }
    // })();
    
    // if(localStorage.getItem('NAVIGATOR_OPEN')) {
    //     show_navigator();
    // }
    
    active_doc_from_hash();
}

function add_history(hash) {
    hash = decodeURIComponent(hash);
    
    if(hash[0] != '#') {
        hash = '#' + hash;
    }
    
    let hashinfo = parse_hash(hash);
    hashinfo.navigator = '';
    let noNavHash = '#' + unparse_hash(hashinfo);
    
    if(historys.length && (historys[historyIndex] == hash)) {
        return;
    }
    
    if(historys[historyIndex] == noNavHash) {
        historys[historyIndex] = hash;
    } else {
        if(historyIndex < historys.length-1) {
            historys.splice(historyIndex+1);
        }
        
        if(!Params.sourceIsDir && hash == '#-') {
            
        } else {
            historys.push(hash);
        }
        
        historyIndex = historys.length-1;
    }
    
    render_history_bar();
}

function left_history() {
    if(historyIndex == 0) {
        return;
    }
    
    historyIndex --;
    let hash = historys[historyIndex];
    render_history_bar();
    active_doc_from_hash(historys[historyIndex], {fromHistory:true});
    return hash;
}

function right_history() {
    if(historyIndex == historys.length - 1) {
        return;
    }
    
    historyIndex ++;
    render_history_bar();
    active_doc_from_hash(historys[historyIndex], {fromHistory:true});
}

function render_history_bar() {
    let historyBar = qone('#historyBar');
    let cur = historyBar.querySelector('.counter .cur');
    let total = historyBar.querySelector('.counter .total');
    let leftBtn = historyBar.querySelector('.left-btn');
    let rightBtn = historyBar.querySelector('.right-btn');
    
    cur.innerHTML  = historyIndex + 1;
    total.innerHTML =historys.length;
    
    if(historyIndex == 0) {
        leftBtn.setAttribute('disabled', 'disabled');
    } else {
        leftBtn.removeAttribute('disabled');
    }
    
    if(historyIndex == historys.length-1) {
        rightBtn.setAttribute('disabled', 'disabled');
    } else {
        rightBtn.removeAttribute('disabled');
    }
}

window.addEventListener('hashchange', function() {
    if(ignoreHashChangeEventCounter) {
        ignoreHashChangeEventCounter --;
        
        if(ignoreHashChangeEventCounter <= 0) {
            ignoreHashChangeEventCounter = 0;
        }
        
        return;
    }
    
    // if(!Params.sourceIsDir) {
    //     let hashRet = parse_hash(window.location.hash);
    //     let navigator = hashRet.navigator ? hashRet.navigator.trim() : '';
    //    
    //     if(navigator) {
    //         let allLi = qall('.file-catalog .navigator li');
    //         allLi = [].slice.call(allLi);
    //         for(let i in allLi) {
    //             let li = allLi[i];
    //             let title = li.getAttribute('title');
    //            
    //             if(title == navigator) {
    //                 ignoreHashChangeEventCounter++;
    //                 window.location.hash = '-';
    //                 li.click();
    //                 break;
    //             }
    //         }
    //     }
    // } else {
    //    
    // }
    
    active_doc_from_hash();
});

window.addEventListener('keydown', function(e) {
    if((e.altKey && !e.shiftKey && !e.ctrlKey) && (e.key == 'ArrowLeft' || e.key == 'ArrowRight')) {
        e.preventDefault();
        e.stopPropagation();
        
        if(e.key == 'ArrowLeft') {
            left_history();
        } else {
            right_history();
        }
    }
});

document.addEventListener('DOMContentLoaded', init);

